package com.boc.ewr.util.controller;

import com.baomidou.mybatisplus.extension.service.IService;
import com.boc.ewr.util.file.annotation.ImportEnumAnnotation;
import com.boc.ewr.util.file.enumeration.ImportEnum;
import com.xkcoding.http.util.StringUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.jeecg.common.api.vo.Result;
import org.jeecg.common.system.base.controller.JeecgController;
import org.jeecg.common.util.CommonUtils;
import org.jeecg.common.util.SpringContextUtils;
import org.jeecgframework.poi.excel.ExcelImportUtil;
import org.jeecgframework.poi.excel.entity.ImportParams;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.multipart.MultipartHttpServletRequest;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Collection;
import java.util.List;
import java.util.Map;

/**
 * @Description: Controller基类
 * @Author: dangzhenghui@163.com
 * @Date: 2019-4-21 8:13
 * @Version: 1.0
 */
@Slf4j
public class ControllerCus<T, S extends IService<T>> extends JeecgController<T, S> {

    /**
     * 通过批量导入excel数据
     *
     */
    public Result<?> importExcel(List<String> showUrls, ImportEnum businessEnum) throws FileNotFoundException {
        boolean tmepFlag = true;
        for (String filePath : showUrls) {
            CommonUtils.filterFileName(filePath);
            File file = FileUtils.getFile(filePath);
            FileInputStream fileInputStream = null;
            try {
                fileInputStream = FileUtils.openInputStream(file);
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
            BufferedInputStream in = new BufferedInputStream(fileInputStream);
            // 获取上传文件对象
            ImportParams params = new ImportParams();
            params.setTitleRows(2);
            params.setHeadRows(1);
            params.setNeedSave(true);
            try {
                List<T> list = ExcelImportUtil.importExcel(in, businessEnum.getEntityName(), params);
                //update-begin-author:taoyan date:20190528 for:批量插入数据
                long start = System.currentTimeMillis();
                //对枚举进行映射
                //TODO 注意一下，如果性能影响很大，建议重写这个excel导入方法
                list.forEach(this::updateEleByEnum);
                //批量导入
                Object serviceObj = SpringContextUtils.getBean(businessEnum.getServiceName());
                Method method = businessEnum.getServiceName().getMethod("initSaveBatch", Collection.class, Boolean.class);
                method.invoke(serviceObj, list, tmepFlag);
                tmepFlag = false;
                log.info("消耗时间" + (System.currentTimeMillis() - start) + "毫秒，数据行数：" + list.size());
            } catch (Exception e) {
                //update-begin-author:taoyan date:20211124 for: 导入数据重复增加提示
                String msg = e.getMessage();
                log.error(msg, e);
                if(msg!=null && msg.indexOf("Duplicate entry")>=0){
                    throw new IllegalArgumentException("文件导入失败:有重复数据！");
                }else{
                    throw new IllegalArgumentException("文件导入失败!" + msg);
                }
            } finally {
                try {
                    fileInputStream.close();
                    in.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return Result.ok("文件导入成功！" );
    }

    /**
     * 通过excel导入数据
     *
     */
    protected Result<?> importExcel(HttpServletRequest request, HttpServletResponse response, Class<T> clazz) {
        MultipartHttpServletRequest multipartRequest = (MultipartHttpServletRequest) request;
        Map<String, MultipartFile> fileMap = multipartRequest.getFileMap();
        for (Map.Entry<String, MultipartFile> entity : fileMap.entrySet()) {
            // 获取上传文件对象
            MultipartFile file = entity.getValue();
            ImportParams params = new ImportParams();
            params.setTitleRows(2);
            params.setHeadRows(1);
            params.setNeedSave(true);
            try {
                List<T> list = ExcelImportUtil.importExcel(file.getInputStream(), clazz, params);
                //update-begin-author:taoyan date:20190528 for:批量插入数据
                long start = System.currentTimeMillis();
                //对枚举进行映射
                //TODO 注意一下，如果性能影响很大，建议重写这个excel导入方法
                list.forEach(this::updateEleByEnum);
                service.saveBatch(list);
                //400条 saveBatch消耗时间1592毫秒  循环插入消耗时间1947毫秒
                //1200条  saveBatch消耗时间3687毫秒 循环插入消耗时间5212毫秒
                log.info("消耗时间" + (System.currentTimeMillis() - start) + "毫秒");
                //update-end-author:taoyan date:20190528 for:批量插入数据
                return Result.ok("文件导入成功！数据行数：" + list.size());
            } catch (Exception e) {
                //update-begin-author:taoyan date:20211124 for: 导入数据重复增加提示
                String msg = e.getMessage();
                log.error(msg, e);
                if(msg!=null && msg.indexOf("Duplicate entry")>=0){
                    return Result.error("文件导入失败:有重复数据！");
                }else{
                    return Result.error("文件导入失败:" + e.getMessage());
                }
                //update-end-author:taoyan date:20211124 for: 导入数据重复增加提示
            } finally {
                try {
                    file.getInputStream().close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return Result.error("文件导入失败！");
    }

    /**
     * 根据注解，修改对应属性的值
     * @param obj
     */
    private void updateEleByEnum(Object obj)  {
        Field[] fields = obj.getClass().getDeclaredFields();
        try {
            for(int i = 1; i < fields.length; i++){
                //序列号不需要，直接跳过
                Field field = fields[i];//属性
                ImportEnumAnnotation enumAnnotation = field.getDeclaredAnnotation(ImportEnumAnnotation.class);
                if(enumAnnotation == null || StringUtil.isEmpty(enumAnnotation.enumName())){
                    //不存在注解的直接跳过
                    continue;
                }
                //获取属性名称和对应的属性值
                String methodGetName = "get" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
                String methodSetName = "set" + field.getName().substring(0, 1).toUpperCase() + field.getName().substring(1);
                Method getMethod = obj.getClass().getMethod(methodGetName);
                Method setMethod = obj.getClass().getMethod(methodSetName, String.class);
                String value = (String)getMethod.invoke(obj); //属性值
                //反射获取枚举类
                Class<Enum> clazz = (Class<Enum>) Class.forName("com.boc.ewr.util.file.enumeration." + enumAnnotation.enumName());
                Method index =clazz.getMethod("getIndex"); //枚举值
                Method val =clazz.getMethod("getValue"); //匹配的中文值
                String defaultVal = enumAnnotation.defaultVal(); //默认值
                Enum[] enumobjs = clazz.getEnumConstants();//枚举列表
                boolean tmpFlag = false; //赋予默认值标志位
                for(Enum enumObj : enumobjs){
                    if(val.invoke(enumObj).equals(value)){
                        setMethod.invoke(obj, index.invoke(enumObj));
                        tmpFlag = true;
                        break;
                    }

                }
                //存在默认值，且没有命中枚举的情况下，赋值默认值
                if(StringUtil.isNotEmpty(defaultVal) && !tmpFlag){
                    setMethod.invoke(obj, defaultVal);
                }
            }
        } catch (Exception e) {
            log.error("枚举映射失败！映射对象是：{}，错误信息：{}", obj.toString(), e);
        }
    }

}
